{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* summary: 第八章实验的代码，神经网络识别手写图像\n",
    "* author: Mr. GAO\n",
    "* date：2022-9-23\n",
    "**********"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 数据准备"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 显示手写图像示例"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x2cbfda6d850>"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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59O6deu0bds25efnKzc3V5s3b1YgENBtt92WlAMAAKSpRDxq+PLLL0e3+fzzz90DDzzgpk2b5q6//nq3atUq19PTc82vwWPYiRnpyvp9Y3DOjob1e5eq42qPYXv+981LGeFwWD6fz7qMtJdi03rN6KmVWdL1PIwX5+3wQqGQcnNzR1xPLzgAgAkCCABgggACAJgggAAAJgggAIAJAggAYIIAAgCYIIAAACYIIACACQIIAGBiVL+OAcDERGsdJBJXQAAAEwQQAMAEAQQAMEEAAQBMEEAAABMEEADABAEEADBBAAEATBBAAAATBBAAwAQBBAAwQS84YIKbCP3d6O2WmrgCAgCYIIAAACYIIACACQIIAGCCAAIAmCCAAAAmCCAAgAkCCABgggACAJgggAAAJmjFk6HiaT0yEVqxpDvm6HK010l/XAEBAEwQQAAAEwQQAMAEAQQAMEEAAQBMEEAAABMEEADABAEEADBBAAEATBBAAAATBBAAwAS94JBS4u15lir9wOjVNnapMpcYP1wBAQBMxBVAjY2NWrhwoXJyclRYWKiVK1eqs7MzZps777xTHo8nZmzYsCGhRQMA0l9cAdTa2qr6+nodOnRI7777ri5evKglS5ZoYGAgZrv169erp6cnOrZv357QogEA6S+ue0Bvv/12zNc7d+5UYWGh2tvbtXjx4ujy66+/Xn6/PzEVAgAy0pjuAYVCIUlSfn5+zPJXXnlFBQUFmj9/vhoaGnT+/PkR9xGJRBQOh2MGACDzjfopuKGhIW3ZskW333675s+fH11+zz33qLy8XCUlJTp69KgeeughdXZ26rXXXht2P42NjXriiSdGWwYAIE153CifH924caPeeustvf/++5o5c+aI2+3fv181NTXq6urS7NmzL1sfiUQUiUSiX4fDYZWWlo6mJIxSOj9CnCqP7qbze5gqUmUukTihUEi5ubkjrh/VFdCmTZv05ptv6uDBg1cMH0mqrq6WpBEDyOv1yuv1jqYMAEAaiyuAnHPavHmzmpqa1NLSooqKiqt+T0dHhySpuLh4VAUCADJTXAFUX1+vXbt2ad++fcrJyVEwGJQk+Xw+TZkyRSdOnNCuXbv0ne98R9OnT9fRo0e1detWLV68WAsWLEjKAQAA0lNc94BG+hntyy+/rPvuu0+nTp3S9773PR07dkwDAwMqLS3VqlWr9POf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s2etSxqTUCgkScrPz5cktbe36+LFizHzOW/ePJWVlaX1fH7xOP/rlVdeUUFBgebPn6+GhgadP3/eoryEuHTpkvbs2aOBgQEFAoFxncuUa0b6RZ999pkuXbqkoqKimOVFRUX6+9//blRV4lVXV2vnzp2aO3euenp69MQTT+iOO+7QsWPHlJOTY11ewgWDQUkadl7/uy5TLFu2TKtXr1ZFRYVOnDihn/3sZ1q+fLna2to0efJk6/LiNjQ0pC1btuj222/X/PnzJf1nPrOzs5WXlxezbTrP53DHKUn33HOPysvLVVJSoqNHj+qhhx5SZ2enXnvtNcNq4/fhhx8qEAhocHBQU6dOVVNTk26++WZ1dHSM21ymfABNFMuXL4/+ecGCBaqurlZ5ebl+//vfa926dYaVYay++93vRv986623asGCBZo9e7ZaWlpUU1NjWNno1NfX69ixY2l/j/JqRjrO+++/P/rnW2+9VcXFxaqpqdGJEyc0e/bs8S5z1ObOnauOjg6FQiH94Q9/UF1dnVpbW8e1hpT/EVxBQYEmT5582RMYvb298vv9RlUlX15enm666SZ1dXVZl5IU/527iTavkjRr1iwVFBSk5dxu2rRJb775pg4cOBDza1P8fr8uXLigvr6+mO3TdT5HOs7hVFdXS1LazWd2drbmzJmjqqoqNTY2qrKyUs8+++y4zmXKB1B2draqqqrU3NwcXTY0NKTm5mYFAgHDypLr3LlzOnHihIqLi61LSYqKigr5/f6YeQ2Hwzp8+HBGz6skffrppzp79mxaza1zTps2bVJTU5P279+vioqKmPVVVVXKysqKmc/Ozk6dPHkyrebzasc5nI6ODklKq/kcztDQkCKRyPjOZUIfaUiSPXv2OK/X63bu3Ok+/vhjd//997u8vDwXDAatS0uYH//4x66lpcV1d3e7P/3pT662ttYVFBS4M2fOWJc2av39/e6DDz5wH3zwgZPknn76affBBx+4f/3rX84555588kmXl5fn9u3b544ePepWrFjhKioq3Oeff25ceXyudJz9/f3uwQcfdG1tba67u9u999577mtf+5q78cYb3eDgoHXp12zjxo3O5/O5lpYW19PTEx3nz5+PbrNhwwZXVlbm9u/f744cOeICgYALBAKGVcfvasfZ1dXlfvGLX7gjR4647u5ut2/fPjdr1iy3ePFi48rj8/DDD7vW1lbX3d3tjh496h5++GHn8XjcH//4R+fc+M1lWgSQc849//zzrqyszGVnZ7tFixa5Q4cOWZeUUGvXrnXFxcUuOzvbffnLX3Zr1651XV1d1mWNyYEDB5yky0ZdXZ1z7j+PYj/yyCOuqKjIeb1eV1NT4zo7O22LHoUrHef58+fdkiVL3IwZM1xWVpYrLy9369evT7v/PA13fJLcyy+/HN3m888/dw888ICbNm2au/76692qVatcT0+PXdGjcLXjPHnypFu8eLHLz893Xq/XzZkzx/3kJz9xoVDItvA4/fCHP3Tl5eUuOzvbzZgxw9XU1ETDx7nxm0t+HQMAwETK3wMCAGQmAggAYIIAAgCYIIAAACYIIACACQIIAGCCAAIAmCCAAAAmCCAAgAkCCABgggACAJgggAAAJv4HjZA3JGicAAcAAAAASUVORK5CYII=",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "\n",
    "img_file = open('./digits/trainingDigits/0_0.txt')\n",
    "img_array = img_file.readlines()\n",
    "\n",
    "img_metrix = np.zeros([32,32])\n",
    "for i in range(32):             # 遍历所有行\n",
    "    for j in range(32):         # 遍历所有列\n",
    "        img_metrix[i, j] = img_array[i][j]\n",
    "\n",
    "plt.imshow(img_metrix, cmap=\"gray\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 将加载的32*32图像展开成一列向量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from os import listdir\n",
    "\n",
    "def img2vector(filename):\n",
    "    return_met = np.zeros([1024], int)  # 定义返回矩阵\n",
    "    fr = open(filename)             # 打开数字文件\n",
    "    lines = fr.readlines()          # 读取文件中的所有数\n",
    "    for i in range(32):             # 遍历所有行\n",
    "        for j in range(32):         # 遍历所有列\n",
    "            return_met[i*32 + j] = lines[i][j]\n",
    "    \n",
    "    return return_met\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 加载训练数据，并将样本标签转化为one-hot向量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "def readDataSet(path):\n",
    "    fileList = listdir(path)                   # 获取文件夹下的所有文件\n",
    "    numFiles = len(fileList)                   # 统计需要读取的文件的数目\n",
    "    dataSet = np.zeros([numFiles, 1024], int)  # 用于存放所有的数字文件\n",
    "    hwLabels = np.zeros([numFiles, 10])        # 用于存放对应的one-hot标签\n",
    "    for i in range(numFiles):                  # 遍历所有的文件\n",
    "        filePath = fileList[i]                 # 获取文件名称/路径\n",
    "        digit = int(filePath.split('_')[0])    # 通过文件名获取标签，注意类型转换\n",
    "        hwLabels[i][digit] = 1.0               # 将对应的one-hot标签置1\n",
    "        dataSet[i] = img2vector(path + '/' + filePath)  # 读取文件内容\n",
    "    return dataSet, hwLabels"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 读取训练集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(1934, 1024)\n",
      "(1934, 10)\n"
     ]
    }
   ],
   "source": [
    "train_dataSet, train_hwLabels = readDataSet('./digits/trainingDigits/')\n",
    "print(train_dataSet.shape)\n",
    "print(train_hwLabels.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 构建并训练网络"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 构建神经网络\n",
    "    * 设置网络的隐藏层数、各隐藏层神经元个数、激活函数、学习率、优化方法、最大迭代次数。\n",
    "    * hidden_layer_sizes 存放的是一个元组，表示第i层隐藏层里神经元的个数。例如：设置3个隐藏层，分别为512、256、128个神经元, 设置元组(512, 256, 128)\n",
    "    * 使用logistic激活函数和adam优化方法，并令初始学习率为0.001\n",
    "    * 可以改动各个参数的取值，查看训练效果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "MLPClassifier(hidden_layer_sizes=(512, 256, 128), learning_rate_init=0.0001,\n",
      "              max_iter=500)\n"
     ]
    }
   ],
   "source": [
    "from sklearn.neural_network import MLPClassifier\n",
    "\n",
    "mlp_classifier = MLPClassifier(hidden_layer_sizes=(512, 256, 128),\n",
    "                                activation='relu',\n",
    "                                solver='adam',\n",
    "                                learning_rate_init=0.0001,\n",
    "                                max_iter=500)\n",
    "print(mlp_classifier)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 训练神经网络\n",
    "    * fit函数能够根据训练集及对应标签集自动设置多层感知机的输入与输出层的神经元个数\n",
    "    * 例如train_dataSet为n*1024的矩阵，train_hwLabels为n*10的矩阵，则fit函数将MLP的输入层神经元个数设为1024，输出层神经元个数为10"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<style>#sk-container-id-1 {color: black;background-color: white;}#sk-container-id-1 pre{padding: 0;}#sk-container-id-1 div.sk-toggleable {background-color: white;}#sk-container-id-1 label.sk-toggleable__label {cursor: pointer;display: block;width: 100%;margin-bottom: 0;padding: 0.3em;box-sizing: border-box;text-align: center;}#sk-container-id-1 label.sk-toggleable__label-arrow:before {content: \"▸\";float: left;margin-right: 0.25em;color: #696969;}#sk-container-id-1 label.sk-toggleable__label-arrow:hover:before {color: black;}#sk-container-id-1 div.sk-estimator:hover label.sk-toggleable__label-arrow:before {color: black;}#sk-container-id-1 div.sk-toggleable__content {max-height: 0;max-width: 0;overflow: hidden;text-align: left;background-color: #f0f8ff;}#sk-container-id-1 div.sk-toggleable__content pre {margin: 0.2em;color: black;border-radius: 0.25em;background-color: #f0f8ff;}#sk-container-id-1 input.sk-toggleable__control:checked~div.sk-toggleable__content {max-height: 200px;max-width: 100%;overflow: auto;}#sk-container-id-1 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {content: \"▾\";}#sk-container-id-1 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-1 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-1 input.sk-hidden--visually {border: 0;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);height: 1px;margin: -1px;overflow: hidden;padding: 0;position: absolute;width: 1px;}#sk-container-id-1 div.sk-estimator {font-family: monospace;background-color: #f0f8ff;border: 1px dotted black;border-radius: 0.25em;box-sizing: border-box;margin-bottom: 0.5em;}#sk-container-id-1 div.sk-estimator:hover {background-color: #d4ebff;}#sk-container-id-1 div.sk-parallel-item::after {content: \"\";width: 100%;border-bottom: 1px solid gray;flex-grow: 1;}#sk-container-id-1 div.sk-label:hover label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-1 div.sk-serial::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 0;bottom: 0;left: 50%;z-index: 0;}#sk-container-id-1 div.sk-serial {display: flex;flex-direction: column;align-items: center;background-color: white;padding-right: 0.2em;padding-left: 0.2em;position: relative;}#sk-container-id-1 div.sk-item {position: relative;z-index: 1;}#sk-container-id-1 div.sk-parallel {display: flex;align-items: stretch;justify-content: center;background-color: white;position: relative;}#sk-container-id-1 div.sk-item::before, #sk-container-id-1 div.sk-parallel-item::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 0;bottom: 0;left: 50%;z-index: -1;}#sk-container-id-1 div.sk-parallel-item {display: flex;flex-direction: column;z-index: 1;position: relative;background-color: white;}#sk-container-id-1 div.sk-parallel-item:first-child::after {align-self: flex-end;width: 50%;}#sk-container-id-1 div.sk-parallel-item:last-child::after {align-self: flex-start;width: 50%;}#sk-container-id-1 div.sk-parallel-item:only-child::after {width: 0;}#sk-container-id-1 div.sk-dashed-wrapped {border: 1px dashed gray;margin: 0 0.4em 0.5em 0.4em;box-sizing: border-box;padding-bottom: 0.4em;background-color: white;}#sk-container-id-1 div.sk-label label {font-family: monospace;font-weight: bold;display: inline-block;line-height: 1.2em;}#sk-container-id-1 div.sk-label-container {text-align: center;}#sk-container-id-1 div.sk-container {/* jupyter's `normalize.less` sets `[hidden] { display: none; }` but bootstrap.min.css set `[hidden] { display: none !important; }` so we also need the `!important` here to be able to override the default hidden behavior on the sphinx rendered scikit-learn.org. See: https://github.com/scikit-learn/scikit-learn/issues/21755 */display: inline-block !important;position: relative;}#sk-container-id-1 div.sk-text-repr-fallback {display: none;}</style><div id=\"sk-container-id-1\" class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>MLPClassifier(hidden_layer_sizes=(512, 256, 128), learning_rate_init=0.0001,\n",
       "              max_iter=500)</pre><b>In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. <br />On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.</b></div><div class=\"sk-container\" hidden><div class=\"sk-item\"><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-1\" type=\"checkbox\" checked><label for=\"sk-estimator-id-1\" class=\"sk-toggleable__label sk-toggleable__label-arrow\">MLPClassifier</label><div class=\"sk-toggleable__content\"><pre>MLPClassifier(hidden_layer_sizes=(512, 256, 128), learning_rate_init=0.0001,\n",
       "              max_iter=500)</pre></div></div></div></div></div>"
      ],
      "text/plain": [
       "MLPClassifier(hidden_layer_sizes=(512, 256, 128), learning_rate_init=0.0001,\n",
       "              max_iter=500)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mlp_classifier.fit(train_dataSet, train_hwLabels)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 测试网络效果"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 读取测试数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(946, 1024)\n"
     ]
    }
   ],
   "source": [
    "test_dataSet, test_hwLabels = readDataSet('./digits/testDigits/')\n",
    "print(test_dataSet.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 使用前面的多层神经网络模型识别测试集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "test_res_recognition = mlp_classifier.predict(test_dataSet)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 统计识别的正确率"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "测试集数字总数： 946 识别错误的数字总数： 37 正确率： 0.9608879492600423\n"
     ]
    }
   ],
   "source": [
    "error_nums = 0\n",
    "test_digit_nums = len(test_dataSet)\n",
    "for i in range(test_digit_nums):\n",
    "    if np.sum(test_res_recognition[i] == test_hwLabels[i]) < 10:\n",
    "        error_nums += 1\n",
    "\n",
    "print(\"测试集数字总数：\", test_digit_nums, \"识别错误的数字总数：\", error_nums,\n",
    "        \"正确率：\", 1 - (error_nums / float(test_digit_nums)))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 参考\n",
    "* https://blog.csdn.net/zzZ_CMing/article/details/79182103\n",
    "* https://blog.51cto.com/u_15060533/4351520"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3.9.13 ('ai_txtbook')",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.13"
  },
  "orig_nbformat": 4,
  "vscode": {
   "interpreter": {
    "hash": "3f7851e38dce13968630152acfada13e17192bdc676945d7b675298112638bc3"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
